package edu.cmich.cps.cps240.partyprincesspalace.hw06;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


/**
 * Represents an input or output pin on a chip.  Chip
 * pins can only connect to wire pins, and always have
 * a chip as a parent.
 * 
 * @author kingm1sa
 * @author holde1ja
 */
public class ChipPin implements Pin, Serializable {
	private static final long serialVersionUID = -8483782895214963606L;
	private String name;
	private Chip parent;
	private WirePin partner;
	private Point location;
	
	
	/**
	 * @return parent, the parent of the chipPin.
	 */
	@Override
	public WorkspaceObj getParent() {
		return this.parent;
	}
	
	
	/**
	 * Sets the parent of the chipPin to p_parent.
	 * @param p_parent, the desired parent of this.
	 */
	@Override
	public void setParent(WorkspaceObj p_parent) {
		if(p_parent instanceof Chip) this.parent = (Chip) p_parent;
	}
	
	
	/**
	 * @return partner, the partner of the chipPin.
	 */
	@Override
	public Pin getPartner() {
		return this.partner;
	}
	
	
	/**
	 * Sets the partner of the chipPin to p_partner.
	 * @param p_partner, the desired partner of this.
	 */
	@Override
	public void setPartner(Pin p_partner) {
		if (p_partner == null)
		{
			partner = null;
			return;
		}
		if(p_partner instanceof WirePin) this.partner = (WirePin) p_partner;
	}
	
	/**
	 * @return name (String) of the chipPin.
	 */
	@Override
	public String getName() {
		return this.name;
	}
	
	
	/**
	 * setName takes p_name (String) passed to it and sets this chipPin's name
	 * to it.
	 * @param p_name (String) is the new name of this chipPin.
	 */
	@Override
	public void setName(String p_name) {
		if (p_name != null){
			this.name = p_name;
		}
	}
	
	
	/**
	 * This method (isInput) checks to see if this ChipPin belongs to one of its
	 * parent's inputs.
	 */
	@Override
	public boolean isInput() {
		 return this.parent.isInputPin(this);
		 
	}
	
	
	/**
	 * This method (isOutput) checks to see if this ChipPin belongs to one of its
	 * parent's outputs.
	 */
	@Override
	public boolean isOutput() {
		return this.parent.isOutputPin(this);
	}
	
	
	
	/**
	 * A standard constructor. Takes in the ChipPin's desired name (String), parent (Chip)
	 * and partner (WirePin). 
	 * @param chipPinName (String), chipPinParent (Chip) and wirePartner (WirePin). These
	 * are used to construct the new ChipPin.
	 */
	public ChipPin(String chipPinName, Chip chipPinParent, WirePin wirePartner){
		if (chipPinName != null){
			this.name = chipPinName;
		}
		this.parent = chipPinParent;
		this.partner = wirePartner;
		this.location = new Point();
	}
	
	
	/**
	 * This constructor does not copy original, per se, it copies the
	 * name and parent of original.
	 * @param original (ChipPin), duplicate some elements of this object (see above).
	 */
	public ChipPin(ChipPin original){
		if (original.name != null){
			this.name = original.name;
		}
		
		this.parent = original.parent;
		this.partner = null;
		this.location = new Point(original.location);
	}
	
	/**
	 * Draws the connection status of the ChipPin.  A red, open circle means the ChipPin is not attached to anything
	 * A green, filled circle means the ChipPin has a connection.
	 * Note that this is a last minute addition.  The rest of the ChipPin's graphics are being done in the Chip class.
	 * This will probably be migrated to the ChipPin class later, if we continue to develop this after the semester
	 * @param g The graphics context which we will be drawing the ChipPin on
	 */
	public void draw(Graphics g)
	{
		Graphics2D g2 = (Graphics2D)g;
		Color c = g2.getColor();

		Ellipse2D circle = new Ellipse2D.Double(this.location.getX() - 2, this.location.getY() - 2,4,4);
		if (this.partner == null)
		{
			g2.setColor(Color.RED);
			g2.draw(circle);
		}
		else
		{
			g2.setColor(Color.GREEN);
			g2.draw(circle);
			g2.fill(circle);
		}
		g2.setColor(c);
		
	}

	/*
	 * (non-Javadoc)
	 * @see edu.cmich.cps.cps240.partyprincesspalace.hw06.Pin#getLocation()
	 */
	@Override
	public Point getLocation() {
		return (new Point(location));
	}


	/*
	 * (non-Javadoc)
	 * @see edu.cmich.cps.cps240.partyprincesspalace.hw06.Pin#setLocation(java.awt.Point)
	 */
	@Override
	public void setLocation(Point p_location) {
			location = new Point(p_location);
	}


	/*
	 * (non-Javadoc)
	 * @see edu.cmich.cps.cps240.partyprincesspalace.hw06.Pin#closeToPin(java.awt.Point)
	 */
	@Override
	public boolean closeToPin(Point point) {
		if ((point.getX() < 0) || (point.getY() < 0)) return false;
		Rectangle rect = new Rectangle();
		rect.x = this.getLocation().x - 5;
		rect.y = this.getLocation().y - 5;
		rect.width = 10;
		rect.height = 10;
		return rect.contains(point);
	}
	
	/**
	 * Is necessary for the Serializable implementation. Passes a serialized version of the object to the
	 * ObjectOutputStream passed in as a parameter.
	 * @param out, an ObjectOutputStream to which the serialized version of this object is passed.
	 */
	@Override
	public void writeObject(ObjectOutputStream out) throws IOException
	{
		out.defaultWriteObject(); 
	}
	
	
	/**
	 * Is necessary for the Serializable implementation. Creates an object from the
	 * ObjectInputStream passed in as a parameter.
	 * @param in, an ObjectInputStream from which to create the object.
	 */
	@Override
	public void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
	{
		// our "pseudo-constructor"
		in.defaultReadObject();
	
	}
}
